package com.cyy.learn.fileMerge

import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.Workbook
import org.apache.commons.collections.IteratorUtils
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVRecord
import org.apache.commons.lang3.StringUtils
import org.apache.poi.poifs.filesystem.POIFSFileSystem
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.Row
import java.io.*
import java.util.*


object fileMergeToolService {
    @Throws(Exception::class)
    fun mergeAction() { //合并操作
//        val fileTypeSelectIndex = fileTypeChoiceBox.selectionModel.selectedIndex

        val filePath = selectFile.text
        val filePaths = filePath.split("\\|".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        val fileList = ArrayList<File>()
        for (path in filePaths) {
            val file = File(path)
            if (file.isDirectory) {
                fileList.addAll(file.listFiles())
//                file.listFiles().forEach { fileList.add(it) }
            } else {
                fileList.add(file)
            }
        }
        var newFilePath: String? = null
        if (fileList[0].isDirectory) {
            if (StringUtils.isNotEmpty(saveFilePath.text)) {
                newFilePath = StringUtils.appendIfMissing(saveFilePath.text, "/", "/", "\\") + "merge_file"
            } else {
                newFilePath = fileList[0].path + "/merge_file"
            }
        } else {
            if (StringUtils.isNotEmpty(saveFilePath.text)) {
                newFilePath = StringUtils.appendIfMissing(saveFilePath.text, "/", "/", "\\") + "merge_" + fileList[0].name
            } else {
                newFilePath = fileList[0].parent + "/merge_" + fileList[0].name
            }
        }
        val resultFile = File(newFilePath)
//        when (fileTypeSelectIndex) {
//            0 -> mergeExcel(fileList, newFilePath)
//            1 -> mergeCsv(fileList, newFilePath)
//            2 -> mergeFile(fileList, newFilePath)
//        }
        when (selectedFileType.value) {
            "Excel" -> mergeExcel(fileList, newFilePath)
            "CSV" -> mergeCsv(fileList, newFilePath)
            "文件" -> mergeFile(fileList, newFilePath)
        }
    }

    @Throws(Exception::class)
    fun mergeExcel(fileList: List<File>, newFilePath: String?) { //拆分Excel表格
        var newFilePath = newFilePath
        newFilePath = StringUtils.appendIfMissing(newFilePath, ".xls", ".xls", ".xlsx")
        val isAddHead = includeHandCheckBox.isSelected
        var newWorkbook: Workbook = HSSFWorkbook()
        if (!newFilePath!!.endsWith(".xls")) {
            newWorkbook = XSSFWorkbook()
        }
        val newSheet = newWorkbook.createSheet()
        var addRowIndex = 0
        var addHeadRecord = false
        for (file in fileList) {
            val filePath = file.path
            val fileInputStream = FileInputStream(filePath)
            try {
                var workbook: Workbook? = null
                if (filePath.endsWith(".xls")) {
                    val fileSystem = POIFSFileSystem(fileInputStream)
                    workbook = HSSFWorkbook(fileSystem)
                } else if (filePath.endsWith(".xlsx")) {
                    workbook = XSSFWorkbook(fileInputStream)
                } else {
                    throw RuntimeException("错误提示: 您设置的Excel文件名不合法!")
                }
                val sheetIterator = workbook!!.sheetIterator()
                while (sheetIterator.hasNext()) {
                    val sheet = sheetIterator.next()
                    val iterator = sheet.rowIterator()
                    var firstRow: Row? = null
                    while (iterator.hasNext()) {
                        val row = iterator.next()
                        if (isAddHead && firstRow == null) {
                            firstRow = row
                            if (!addHeadRecord) {
                                addHeadRecord = true
                                val newRow = newSheet.createRow(addRowIndex++)
                                copyRow(firstRow, newRow)
                            }
                        } else {
                            val newRow = newSheet.createRow(addRowIndex++)
                            copyRow(row, newRow)
                        }
                    }
                }
            } finally {
                fileInputStream.close()
            }
        }
        saveFile(newWorkbook, newFilePath)
        newWorkbook.close()
    }

    @Throws(Exception::class)
    fun mergeCsv(fileList: List<File>, newFilePath: String?) {
        var newFilePath = newFilePath
        newFilePath = StringUtils.appendIfMissing(newFilePath, ".csv", ".csv", ".CSV")
        val isAddHead = includeHandCheckBox.isSelected
        val printer = CSVFormat.DEFAULT.print(PrintWriter(newFilePath!!))
        var addHeadRecord = false
        for (file in fileList) {
            val fileReader = FileReader(file)
            val parser = CSVFormat.DEFAULT.parse(fileReader)
            val iterator = parser.iterator()
            var firstRecord: CSVRecord? = null
            while (iterator.hasNext()) {
                val record = iterator.next()
                if (isAddHead && firstRecord == null) {
                    firstRecord = record
                    if (!addHeadRecord) {
                        addHeadRecord = true
                        printer.printRecord(IteratorUtils.toList(record.iterator()).toTypedArray())
                    }
                } else {
                    printer.printRecord(IteratorUtils.toList(record.iterator()).toTypedArray())
                }
            }
            fileReader.close()
        }
        printer.flush()
        printer.close()
    }

    @Throws(Exception::class)
    fun mergeFile(fileList: List<File>, newFilePath: String?) {
        val resultFile = File(newFilePath)
        try {
            val resultFileChannel = FileOutputStream(resultFile, true).channel
            for (file in fileList) {
                val blk = FileInputStream(file).channel
                resultFileChannel.transferFrom(blk, resultFileChannel.size(), blk.size())
                blk.close()
            }
            resultFileChannel.close()
        } catch (e: Exception) {
            Error("合并文件失败：", e)
        }

    }

    private fun saveFile(workbook: Workbook, filePath: String) {
        var filePath = filePath
        if (workbook is HSSFWorkbook) {
            filePath = StringUtils.appendIfMissing(filePath, ".xls", ".xls", ".xlsx")
        } else if (workbook is XSSFWorkbook) {
            filePath = StringUtils.appendIfMissing(filePath, ".xlsx", ".xls", ".xlsx")
        }
        var out: FileOutputStream? = null
        try {
            out = FileOutputStream(File(filePath))
            workbook.write(out)
            workbook.close()
        } catch (e: IOException) {
            Error("报错文件失败：", e)
        } finally {
            try {
                out?.close()
            } catch (e: IOException) {
                Error("FileOutputStream close Fail" + e.message)
            }

        }
    }

    private fun copyRow(row: Row?, newRow: Row) {
        try {
            newRow.height = row!!.height
            newRow.heightInPoints = row!!.heightInPoints
            newRow.zeroHeight = row!!.zeroHeight
            newRow.rowStyle = row!!.rowStyle
        } catch (e: Exception) {

        }

        row!!.cellIterator().forEachRemaining { cell -> setCellValue(cell, newRow.createCell(cell.columnIndex, cell.cellType)) }
    }

    private fun setCellValue(cell: Cell, newCell: Cell) {
        try {
            newCell.cellStyle = cell.cellStyle
        } catch (e: Exception) {
        }

        // 以下是判断数据的类型
        when (cell.cellType) {
            CellType.BLANK -> newCell.setBlank()   // 空值
            CellType.BOOLEAN -> newCell.setCellValue(cell.booleanCellValue)// 布尔型
            CellType.FORMULA -> newCell.cellFormula = cell.cellFormula// 公式型
            CellType.NUMERIC -> newCell.setCellValue(cell.numericCellValue)// 数值型
            CellType.STRING -> newCell.setCellValue(cell.stringCellValue)// 字符型
            else -> newCell.setBlank()
        }
    }
}